using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Reflection;

namespace PlanetWPF.Toolbelt.Controls
{
    /// <summary>
    /// Provides the state of the current cell.
    /// </summary>
    public enum CellState
    {
        Default = 0,
        Edit = 1
    }


    /// <summary>
    /// Represents a single cell in a <see cref="PowerGrid"/>. The cell displays
    /// data based on the Item (retrieved from the <see cref="PowerGridRow"/> that owns it)
    /// and the <see cref="PowerGridColumn"/> assigned to it.
    /// </summary>
    public class PowerGridCell : Control
    {
        #region Private Member Variables

        private bool _canBeSelected = false;
        private bool _dragSelection = false;
        private bool _isLoaded = false;

        #endregion

        #region Routed Events
        /// <summary>
        /// Tunneling <see cref="RoutedEvent"/> that is fired just before a <see cref="PowerGridCell"/> is selected.
        /// </summary>
        public static readonly RoutedEvent PreviewCellSelectedEvent;
        /// <summary>
        /// Tunneling <see cref="RoutedEvent"/> that is fired just before a <see cref="PowerGridCell"/> is deselected.
        /// </summary>
        public static readonly RoutedEvent PreviewCellDeselectedEvent;

        /// <summary>
        /// A <see cref="RoutedEvent"/> that notifies listeners that this cell has been
        /// selected.
        /// </summary>
        public static readonly RoutedEvent CellSelectedEvent;

        /// <summary>
        /// A <see cref="RoutedEvent"/> that notifies listeners that this cell has been
        /// deselected.
        /// </summary>
        public static readonly RoutedEvent CellDeselectedEvent;

        #endregion

        #region CLR RoutedEvents
        public event RoutedEventHandler PreviewCellDeselected
        {
            add { AddHandler(PreviewCellDeselectedEvent, value); }
            remove { RemoveHandler(PreviewCellDeselectedEvent, value); }
        }

        public event RoutedEventHandler CellDeselected
        {
            add { AddHandler(CellDeselectedEvent, value); }
            remove { RemoveHandler(CellDeselectedEvent, value); }
        }

        public event RoutedEventHandler PreviewCellSelected
        {
            add { AddHandler(PreviewCellSelectedEvent, value); }
            remove { RemoveHandler(PreviewCellSelectedEvent, value); }
        }

        public event RoutedEventHandler CellSelected
        {
            add { AddHandler(CellSelectedEvent, value); }
            remove { RemoveHandler(CellSelectedEvent, value); }
        }

        #endregion


        #region Static Constructor
        /// <summary>
        /// Static constructor for <see cref="PowerGridCell"/>. Responsible for
        /// initializing the Dependency Properties and <see cref="RoutedEvent"/>s, and
        /// for Registering Handlers for RoutedEvents.
        /// </summary>
        static PowerGridCell()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(PowerGridCell), new FrameworkPropertyMetadata(typeof(PowerGridCell)));
            CellColumnProperty = DependencyProperty.Register("CellColumn", typeof(PowerGridColumn), typeof(PowerGridCell), new FrameworkPropertyMetadata(null, CellColumnChanged));
            CellTypeProperty = DependencyProperty.Register("CellType", typeof(PowerGridColumnType), typeof(PowerGridCell), new UIPropertyMetadata(PowerGridColumnType.Text));
            CellValueProperty = DependencyProperty.Register("CellValue", typeof(object), typeof(PowerGridCell), new FrameworkPropertyMetadata(null, CellValueChanged));
            CellItemProperty = DependencyProperty.Register("Item", typeof(Object), typeof(PowerGridCell), new FrameworkPropertyMetadata(null, ItemChanged));
            CellRowProperty = DependencyProperty.Register("ParentRow", typeof(PowerGridRow), typeof(PowerGridCell), new UIPropertyMetadata(null, ParentRowChanged));
            CellSelectedProperty = DependencyProperty.Register("Selected", typeof(Boolean), typeof(PowerGridCell), new FrameworkPropertyMetadata(false, SelectedChanged));
            CellPathProperty = DependencyProperty.Register("CellPath", typeof(String), typeof(PowerGridCell), new UIPropertyMetadata(""));
            PreviewCellSelectedEvent = EventManager.RegisterRoutedEvent("PreviewCellSelected", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(PowerGridCell));
            CellSelectedEvent = EventManager.RegisterRoutedEvent("CellSelected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(PowerGridCell));
            PreviewCellDeselectedEvent = EventManager.RegisterRoutedEvent("PreviewCellDeselected", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(PowerGridCell));
            CellDeselectedEvent = EventManager.RegisterRoutedEvent("CellDeselected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(PowerGridCell));
            EventManager.RegisterClassHandler(typeof(PowerGridCell), FrameworkElement.LoadedEvent, new RoutedEventHandler(LoadedHandler));
        }

        public PowerGridCell()
        {
            Loaded += LoadedHandler;
        }
        #endregion

        #region Dependency Properties
        /// <summary>
        /// Holds the <see cref="PowerGridColumn"/> associated with this cell.
        /// </summary>
        public static readonly DependencyProperty CellColumnProperty;
        /// <summary>
        /// Holds the value that this cell will display.
        /// </summary>
        public static readonly DependencyProperty CellValueProperty;
        /// <summary>
        /// Holds the Object associated with this cell.
        /// </summary>
        public static readonly DependencyProperty CellItemProperty;
        /// <summary>
        /// Holds an indicator of whether the cell is Selected or not.
        /// </summary>
        public static readonly DependencyProperty CellSelectedProperty;

        public static readonly DependencyProperty CellRowProperty;
        public static readonly DependencyProperty CellTypeProperty;
        public static readonly DependencyProperty CellPathProperty;
        #endregion


        #region Public Properties


        public Object Item
        {
            get { return (Object)GetValue(CellItemProperty); }
            set { SetValue(CellItemProperty, value); }
        }

        public object CellValue
        {
            get { return (object)GetValue(CellValueProperty); }
            set { SetValue(CellValueProperty, value); }
        }

        public PowerGridColumn CellColumn
        {
            get { return (PowerGridColumn)GetValue(CellColumnProperty); }
            set { SetValue(CellColumnProperty, value); }
        }

        public PowerGridRow ParentRow
        {
            get { return (PowerGridRow)GetValue(CellRowProperty); }
            set
            {
                SetValue(CellRowProperty, value);
            }
        }

        public Boolean Selected
        {
            get { return (Boolean)GetValue(CellSelectedProperty); }
            set { SetValue(CellSelectedProperty, value); }
        }

        public PowerGridColumnType CellType
        {
            get { return (PowerGridColumnType)GetValue(CellTypeProperty); }
            set { SetValue(CellTypeProperty, value); }
        }


        #endregion

        #region Prop Changed Handlers

        private static void CellValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //TODO: Implement this event handler.
        }



        public String CellPath
        {
            get { return (String)GetValue(CellPathProperty); }
            set { SetValue(CellPathProperty, value); }
        }



        private static void ColumnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        private static void CellColumnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PowerGridCell tmpGridCell = d as PowerGridCell;
            if (tmpGridCell != null)
            {
                if (tmpGridCell._isLoaded)
                {
                    tmpGridCell.InitializeCell();
                }
            }
        }
        private static void ItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PowerGridCell tmpGridCell = d as PowerGridCell;
            if (tmpGridCell != null)
            {
                if (tmpGridCell._isLoaded)
                {
                    tmpGridCell.InitializeCell();
                }
            }
        }

        protected virtual void OnSelectedChanged(DependencyPropertyChangedEventArgs e)
        {
            if (((bool)e.NewValue) == true)
            {
                RoutedEventArgs args = new RoutedEventArgs(PreviewCellSelectedEvent);
                RaiseEvent(args);
                if (!args.Handled)
                {
                    RaiseEvent(new RoutedEventArgs(CellSelectedEvent));
                }
            }
            else if (((bool)e.NewValue) == false)
            {
                RoutedEventArgs args = new RoutedEventArgs(PreviewCellDeselectedEvent);
                RaiseEvent(args);
                if (!args.Handled)
                {
                    RaiseEvent(new RoutedEventArgs(CellDeselectedEvent));
                }
            }

        }

        private static void SelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PowerGridCell tmpGridCell = d as PowerGridCell;
            if (tmpGridCell != null)
            {
                tmpGridCell.OnSelectedChanged(e);
            }
        }

        private static void ParentRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PowerGridCell tmpgridcell = d as PowerGridCell;
            if (tmpgridcell != null)
            {
                PowerGridRow tmprow = e.OldValue as PowerGridRow;
                if (tmprow != null)
                {
                    tmprow.RemoveCell(tmpgridcell);
                }
                tmprow = e.NewValue as PowerGridRow;
                if (tmprow != null)
                {
                    tmprow.AddCell(tmpgridcell);
                }
            }
        }

        #endregion



        /// <summary>
        /// Handler for the <see cref="Control.LoadedEvent"/>. Responsible
        /// for calling the <see cref="InitializeCell"/> virtual function.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void LoadedHandler(object sender, RoutedEventArgs e)
        {
            PowerGridCell tmpcell = sender as PowerGridCell;

            if (tmpcell != null)
            {
                tmpcell._isLoaded = true;
                tmpcell.InitializeCell();
            }
        }



        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
            }
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (!e.Handled)
            {
                _canBeSelected = true;
                e.Handled = true;
            }
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (_canBeSelected && (e.LeftButton == MouseButtonState.Pressed))
            {
                Selected = true;
            }
            _canBeSelected = false;
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (!e.Handled)
            {
                if (_canBeSelected)
                {
                    //Selected = true;
                    if (CellColumn.ColumnType == PowerGridColumnType.RowHeader)
                    {

                        foreach (PowerGridCell cell in ParentRow.ChildCells)
                        {
                            cell.Selected = true;
                        }
                    }

                    if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                    {
                        ParentRow.ParentGrid.SelectRange(this);
                    }

                    else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                    {
                        Selected = true;

                    }
                    else
                    {
                        //first clear all previous selections
                        //then select this one.
                        ParentRow.ParentGrid.ClearSelectedCells();
                        Selected = true;
                    }
                    _canBeSelected = false;
                }
            }
            base.OnMouseLeftButtonUp(e);
        }

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
        }

        /// <summary>
        /// This function allows the cell to set its <see cref="CellValue"/>
        /// according to its logic.
        /// </summary>
        /// <remarks>
        /// Inheritors should override this method if they are
        /// implementing custom display and/or binding logic. 
        /// See <see cref="PowerGridHeaderCell"/> for an example.
        /// </remarks>
        protected virtual void InitializeCell()
        {
            switch (CellType)
            {
                case PowerGridColumnType.Image:

                    PropertyInfo property = Item.GetType().GetProperty(CellPath);
                    Object value = property.GetValue(Item, null);
                    if (value != null)
                    {
                        Image img = value as Image;
                        if (img != null)
                        {
                            SetValue(CellValueProperty, img);
                            break;
                        }
                        String uri = value as String; //WTF why am I getting the value again the hard way?? property.GetValue(Item, null) as String;
                        if (uri != null)
                        {
                            SetValue(
                                CellValueProperty,
                                new BitmapImage(
                                    new Uri(
                                        uri,UriKind.Relative)));
                            break;
                        }
                        throw new NotSupportedException("A PowerGridCell with CellType set to Image must contain a string or an Image or be null");
                    }
                    else
                    {
                        SetValue(CellValueProperty, value);
                        break;
                    }
                default:
                    Binding tmpBinding = new Binding(CellPath);
                    tmpBinding.Source = Item;
                    SetBinding(CellValueProperty, tmpBinding);
                    break;
            }
        }

    }

}
